﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ITAP.ShprossesBuilder.Modelling.Components;
using System.Drawing;
using ITAP.ShprossesBuilder.Editor;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Operations
{
    public class OperationOffsetFromModelBounds : IOperation
    {
        private ModelCell cell;
        private ModelControl modelControl;
        #region IOperation Members

        public string Name
        {
            get { return "Смещение компонента относительно сторон модели"; }
        }

        public OperationGroup OperationGroup
        {
            get { return OperationGroup.Other; }
        }

        public System.Drawing.Image Thumbnail
        {
            get { return Resources.MoveWithOffsetRelativeToBounds.ToBitmap(); }
        }

        public void Execute(ModelControl modelControl)
        {

            this.modelControl = modelControl;

            ModelCell cell = this.modelControl.ModelContainer.ActiveCell as ModelCell;
            if (cell == null)
                return;

            this.cell = cell;
            if (modelControl.ModelContainer.SelectedComponentsStack.Count == 0)
                return;

            ContextMenuStrip menuStrip = new ContextMenuStrip();

            EventHandler handler = new EventHandler(OnItemClick);
            ToolStripItem right = new ToolStripMenuItem("Отступ справа", null, handler);
            right.Tag = OffsetTo.Right;
            menuStrip.Items.Add(right);
            ToolStripItem up = new ToolStripMenuItem("Отступ сверху", null, handler);
            up.Tag = OffsetTo.Up;
            menuStrip.Items.Add(up);
            ToolStripItem left = new ToolStripMenuItem("Отступ слева", null, handler);
            left.Tag = OffsetTo.Left;
            menuStrip.Items.Add(left);
            ToolStripItem down = new ToolStripMenuItem("Отступ снизу", null, handler);
            down.Tag = OffsetTo.Down;
            menuStrip.Items.Add(down);

            menuStrip.Show(Cursor.Position);
        }

        private void OnItemClick(object sender, EventArgs e)
        {
            ToolStripItem item = sender as ToolStripItem;
            OffsetTo offset = (OffsetTo)item.Tag;

            RectangleF modelBoundingBox = cell.Model.BoundingBox;

            SelectAlignForm alignForm = new SelectAlignForm();
            if (alignForm.ShowDialog() != DialogResult.OK)
                return;

            RectangleF alignBoundingBox;

            switch (alignForm.Align)
            {
                case AlignRelative.ToInnerModelSize:
                    alignBoundingBox = new RectangleF(modelBoundingBox.X + (float)cell.Model.SpacerWidth, 
                        modelBoundingBox.Y + (float)cell.Model.SpacerWidth, 
                        modelBoundingBox.Width - (float)(2 * cell.Model.SpacerWidth), 
                        modelBoundingBox.Height - (float)(2 * cell.Model.SpacerWidth));
                    break;
                case AlignRelative.ToModelSize:
                    alignBoundingBox = modelBoundingBox;
                    break;
                case AlignRelative.ToModelCellSize:
                    alignBoundingBox = cell.BoundingBox;
                    break;
                default:
                    throw new Exception();
            }

            foreach (IComponent selectedComponent in this.modelControl.ModelContainer.SelectedComponentsStack)
            {
                
                if(selectedComponent is ShprossConnector)
                {
                    ModelPoint destination = this.GetMoveToPoint(selectedComponent.Position, offset, alignBoundingBox, alignForm.Offset);
                    selectedComponent.MoveTo(destination);
                }
                else if (selectedComponent is Shpross)
                {
                    Shpross shpross = selectedComponent as Shpross;
                    if (shpross.SelectedPoint == ShprossPoints.Start)
                    {
                        ModelPoint position = (selectedComponent as Shpross).SelectedPointPosition;
                        ModelPoint destination = this.GetMoveToPoint(position, offset, alignBoundingBox, alignForm.Offset);
                        shpross.MoveStartPointTo(destination);
                    }
                    else if (shpross.SelectedPoint == ShprossPoints.End)
                    {
                        ModelPoint position = (selectedComponent as Shpross).SelectedPointPosition;
                        ModelPoint destination = this.GetMoveToPoint(position, offset, alignBoundingBox, alignForm.Offset);
                        shpross.MoveEndPointTo(destination);
                    }
                    else if (shpross.SelectedPoint == ShprossPoints.Center)
                    {
                        ModelPoint position = (selectedComponent as Shpross).SelectedPointPosition;
                        ModelPoint destination = this.GetMoveToPoint(position, offset, alignBoundingBox, alignForm.Offset);
                        shpross.MoveTo(destination);
                    }
                }
            }
            modelControl.UpdateModel();
        }

        private ModelPoint GetMoveToPoint(ModelPoint source, OffsetTo offset, RectangleF rectangle, double offsetValue)
        {
            ModelPoint moveToPoint = null;
            switch (offset)
            {
                case OffsetTo.Right:
                    moveToPoint = new ModelPoint(rectangle.X + rectangle.Width, source.Y);
                    moveToPoint = ModelCalculations.GetOffsetPoint(moveToPoint, new ModelVector(-offsetValue, 0));
                    break;
                case OffsetTo.Up:
                    moveToPoint = new ModelPoint(source.X, rectangle.Y + rectangle.Height);
                    moveToPoint = ModelCalculations.GetOffsetPoint(moveToPoint, new ModelVector(0, -offsetValue));
                    break;
                case OffsetTo.Left:
                    moveToPoint = new ModelPoint(rectangle.X, source.Y);
                    moveToPoint = ModelCalculations.GetOffsetPoint(moveToPoint, new ModelVector(offsetValue, 0));
                    break;
                case OffsetTo.Down:
                    moveToPoint = new ModelPoint(source.X, rectangle.Y);
                    moveToPoint = ModelCalculations.GetOffsetPoint(moveToPoint, new ModelVector(0, offsetValue));
                    break;
            }
            return moveToPoint;
        }   

        public bool CanUndo
        {
            get { return true; }
        }

        #endregion
    }
}
